#include "basic/types.h"
#include "game.h"
#include "loc/rva.h"

void Game::destroy(uint8 bag_index, uint8 slot) {
  if (bag_index > 4) {
    return;
  }
  uint64 rcx[6]{0};
  rcx[0] = base_ + RVA_DESTROY_RCX_BASE;
  rcx[4] = (uint64)rcx + 0x28;
  if (bag_index == 0) {
    *((byte *)rcx + 0x2C) = 0xFF;
    *((byte *)rcx + 0x2D) = 0x23 + slot;
  } else {
    *((byte *)rcx + 0x2C) = 0x1D + bag_index;
    *((byte *)rcx + 0x2D) = slot;
  }
  uint64 addr{base_ + RVA_COMMON_SEND_CALL};
  uint64 args[10]{addr, (uint64)rcx};
  send_call(args);
}

void Game::sell(uint64 npc_id1, uint64 npc_id2, uint64 item_id1,
                uint64 item_id2) {
  uint64 rcx[9]{0};
  rcx[0] = base_ + RVA_SELL_RCX_BASE;
  rcx[4] = npc_id1;
  rcx[5] = npc_id2;
  rcx[6] = item_id1;
  rcx[7] = item_id2;
  uint64 addr{base_ + RVA_COMMON_SEND_CALL};
  uint64 args[10]{addr, (uint64)rcx};
  send_call(args);
}

// bag_index: 0 主背包, 从右到左 1-4 背包
// container_slot: 从 0 开始. 在函数内部, 主背从 0x23 开始; 背包从 0 开始;
// equip_slot: 从 0 开始. 比如手是 9, lua api 中是 10.
void Game::equip(uint8 bag_index, uint8 container_slot, uint8 equip_slot) {
  if (bag_index > 4) {
    return;
  }
  uint64 rcx_param[8]{0};
  uint8 arr[4]{0};
  rcx_param[4] = (uint64)arr;
  rcx_param[5] = 2;
  rcx_param[6] = 2;
  if (bag_index == 0) {
    rcx_param[0] = base_ + RVA_EQUIP_RCX_BASE + 0x20;
    container_slot += 0x23;
    arr[0] = 0xFF;
    arr[1] = equip_slot;
    arr[2] = 0xFF;
    arr[3] = container_slot;
    *((byte *)rcx_param + 0x38) = equip_slot;
    *((byte *)rcx_param + 0x39) = container_slot;
  } else {
    rcx_param[0] = base_ + RVA_EQUIP_RCX_BASE;
    bag_index += 0x1D;
    arr[0] = 0xFF;
    arr[1] = equip_slot;
    arr[2] = bag_index;
    arr[3] = container_slot;
    *((byte *)rcx_param + 0x38) = 0xFF;
    *((byte *)rcx_param + 0x39) = bag_index;
    *((byte *)rcx_param + 0x3A) = equip_slot;
    *((byte *)rcx_param + 0x3B) = container_slot;
  }
  uint64 rcx{(uint64)rcx_param};
  uint64 addr{base_ + RVA_COMMON_SEND_CALL};
  uint64 args[10]{addr, rcx};
  send_call(args);
}

void Game::send_mail(uint64 mailbox, const std::string &receiver,
                     const std::string &subject, const std::string &content,
                     const std::vector<uint64> items, const uint32 gold) {
  uint64 rcx_param[333]{0};
  uint64 rcx_base{base_ + RVA_SEND_MAIL_RCX_BASE};
  rcx_param[0] = rcx_base;
  char *prcx = (char *)rcx_param;
  auto [id1, id2] = get_id(mailbox);
  *(uint64 *)(prcx + 0x20) = id1;
  *(uint64 *)(prcx + 0x28) = id2;
  memcpy(prcx + 0x30, receiver.c_str(), receiver.size());
  memcpy(prcx + 0x162, subject.c_str(), subject.size());
  memcpy(prcx + 0x263, content.c_str(), content.size());
  *(uint32 *)(prcx + 0xA34) = 0x29;
  const uint32 num_limit{0x10};
  uint64 attachments[num_limit * 3] = {0};
  uint32 index{0};
  for (uint64 item : items) {
    auto [id1, id2] = get_id(item);
    attachments[index * 3] = index;
    attachments[index * 3 + 1] = id1;
    attachments[index * 3 + 2] = id2;
    index++;
    if (index >= 0x10) {
      break;
    }
  }
  *(uint64 *)(prcx + 0xA38) = (uint64)attachments;
  *(uint64 *)(prcx + 0xA40) = (uint64)index;
  *(uint64 *)(prcx + 0xA48) = (uint64)index;
  *(uint64 *)(prcx + 0xA50) = (uint64)gold;
  uint64 rcx{(uint64)rcx_param};
  uint64 addr{base_ + RVA_COMMON_SEND_CALL};
  uint64 args[10]{addr, rcx};
  send_call(args);
}

// flag=1 左键; flag=4 右键; 默认是  1.
// 左键主要选择 unit
// 右键时可以捡尸体/钓鱼/开门/采矿/挖草药/开宝箱
void Game::select(uint64 id1, uint64 id2, uint32 flag) {
  uint64 addr{base_ + RVA_SELECT_CALL};
  uint64 rcx[3]{id1, id2, flag};
  uint64 args[10]{addr, (uint64)rcx};
  send_call(args);
}

void Game::macro(const std::string &content) {
  uint64 addr{base_ + RVA_MACRO_CALL};
  uint64 rcx{base_ + RVA_MACRO_BASE};
  uint64 rdx[1]{(uint64)content.c_str()};
  uint64 args[10]{addr, rcx, (uint64)rdx};
  send_call(args);
}

// flag=1 是左键点击, flag=4 是右键点击(移动); 默认是 1.
void Game::click(float x, float y, float z, uint32 flag) {
  uint64 addr{base_ + RVA_CLICK_CALL};
  uint32 rcx[8]{0, 0, 0, 0, *(uint32 *)&x, *(uint32 *)&y, *(uint32 *)&z, flag};
  uint64 args[10]{addr, (uint64)rcx};
  send_call(args);
}
